home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource5
/
357_01
/
cstar1.exe
/
UTL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-18
|
12KB
|
676 lines
/*
C* preprocessor -- utility routines.
Source: utl.c
Started: October 7, 1985
Version:
February 20, 1987
March 7, 1989
PUBLIC DOMAIN SOFTWARE
The CSTAR program was placed in the public domain on June 15, 1991,
by its author and sole owner,
Edward K. Ream
1617 Monroe Street
Madison, WI 53711
(608) 257-0802
CSTAR may be used for any commercial or non-commercial purpose.
See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
*/
#include "cstar.h"
/*
Externally visible routines:
*/
int char_val (register char *s);
void conv2s (int a, char *s);
void convl2s (long a, char *s);
void conul2sc (unsigned long n, char *s, int c);
void conl2h (unsigned long n, char *s, int c);
void fatal (char * message);
void revcpy (char *s1, char *s2);
void scan_number (int base);
void skip_bl (void);
bool skip_crlf (void);
void skip_1line (void);
void skip_past (void);
void skip_pp (void);
void skip_ws (void);
void t_error (char * message);
void t_2error (char * mess1, char *mess2);
void t_3serr (struct node *p, char * mess1, char *mess2, char *mess3);
void t_warning (char * message);
void t_2warning (char * mess1, char *mess2);
void t_help (char * message);
void t_2help (char * mess1, char *mess2);
void g_error (struct node * p, char * message);
void g_help (struct node *p, char * message);
unsigned int str_val (unsigned char *d);
/*
Internal routines:
*/
static bool is_base_digit (int base);
/*
Return the value of a character constant.
*/
int
char_val(register char *s)
{
int val;
TRACEPB("char_val", printf("(%s)\n", s));
if (*s != '\\') {
RETURN_INT("char_val", (int) *s);
}
s++;
switch (*s) {
case 'b': RETURN_INT("char_val", '\b');
case 'f': RETURN_INT("char_val", '\f');
case 'n': RETURN_INT("char_val", '\n');
case 'r': RETURN_INT("char_val", '\r');
case 't': RETURN_INT("char_val", '\t');
case '\'': RETURN_INT("char_val", '\'');
case '\\': RETURN_INT("char_val", '\\');
default:
if (*s < '0' || *s > '7') {
RETURN_INT("char_val", (int)*s);
}
val = 0;
while (*s >= '0' && *s <= '7') {
val = val * 8 + (int)*s - '0';
s++;
}
RETURN_INT("char_val", val);
}
}
/*
Convert a signed integer n to a string s[].
The length of s must be large enough to hold the result.
*/
void
conv2s(int a, register char *s)
{
register char *d, *ss;
register int sn;
register unsigned long n;
char temp [INT_DIGITS];
SL_DISABLE();
/* Do the sign and handle 0x8000 correctly */
if (a >= 0) {
sn = 0;
/* these casts ARE NOT redundant: DO NOT fix them! */
/* see note in lint.doc about unsigned extending casts */
n = (unsigned long) (long) a;
}
else {
sn = 1;
n = (unsigned long) (long) (-a);
}
/* put digits in reverse order into temp */
d = &temp[0];
*d++ = 0;
if (n) while (n) {
/* NOTE: in assembly, we would divide once */
*d++ = (char)(n % 10) + '0';
n = n / 10;
}
else {
*d++ = '0';
}
/* insert the sign */
if (sn) {
*d++ = '-';
}
/* Reverse temp into s. */
ss = s;
/* -----
while(*ss++ = *--d) {};
----- */
do {
*ss++ = *--d;
}
while (*d);
TRACEP("conv2s", printf("converts %d to <%s>\n", a, s));
}
/*
Convert a long n to a string s[].
The length of s must be large enough to hold the result.
*/
void
convl2s(long a, register char *s)
{
register char *d, *ss;
register int sn;
register unsigned long n;
char temp [LONG_DIGITS];
SL_DISABLE();
/* Do the sign and handle 0x80000000 correctly */
if (a >= 0) {
sn = 0;
n = (unsigned long) a;
}
else {
sn = 1;
n = (unsigned long) (-a);
}
/* put digits in reverse order into temp */
d = &temp[0];
*d++ = 0;
if (n) while (n) {
/* NOTE: in assembly, we would divide once */
*d++ = (char)(n % 10) + '0';
n = n / 10;
}
else {
*d++ = '0';
}
/* insert the sign */
if (sn) {
*d++ = '-';
}
/* Reverse temp into s. */
ss = s;
/* -----
while(*ss++ = *--d) {};
----- */
do {
*ss++ = *--d;
}
while (*d);
TRACEP("convl2s", printf("converts %ld to <%s>\n", a, s));
}
/*
Convert a long n to a string s[], minimum digit count c.
The length of s must be large enough to hold any result.
*/
void
conul2sc(register unsigned long n, register char *s, register int c)
{
register char *d, *ss;
char temp [LONG_DIGITS];
SL_DISABLE();
/* put digits in reverse order into temp */
d = &temp[0];
*d++ = 0;
while (n) {
/* NOTE: in assembly, we would divide once */
*d++ = (char)(n % 10) + '0';
n /= 10;
if (c > 0) {
c--;
}
}
while (c > 0) {
c--;
*d++ = '0';
}
/* Reverse temp into s. */
ss = s;
/* -----
while(*ss++ = *--d) {};
----- */
do {
*ss++ = *--d;
}
while (*d);
TRACEP("conul2sc", printf("converts %lu, count %d to <%s>\n", n, c, s));
}
/*
Convert a long n to a hex string s[], minimum digit count c.
The length of s must be large enough to hold any result.
*/
void
conl2h(register unsigned long n, register char *s, register int c)
{
register char *d, *ss;
char temp [LONG_DIGITS];
SL_DISABLE();
/* put digits in reverse order into temp */
d = &temp[0];
*d++ = 0;
while (n) {
*d = ((char)n & 15) + '0';
if (*d > '9') {
*d += 7;
}
d++;
n >>= 4;
if (c > 0) {
c--;
}
}
while (c > 0) {
c--;
*d++ = '0';
}
/* Reverse temp into s. */
ss = s;
/* -----
while(*ss++ = *--d) {};
----- */
do {
*ss++ = *--d;
}
while (*d);
TRACEP("conl2h", printf("converts %lu, count %d to <%s>\n", n, c, s));
}
/*
Give an error message and exit.
*/
void
fatal(char * message)
{
SL_DISABLE();
printf("fatal error: ");
t_error(message);
sysabort();
}
/*
Return true if the global ch is a digit in the indicated base.
Return the value of the digit in digit_val;
*/
static unsigned char digit_val;
static bool
is_base_digit(register int base)
{
TRACEPB("is_base_digit", printf("(%d)\n", base));
if (ch >= '0' && ch <= '9') {
digit_val = ch - '0';
RETURN_BOOL("is_base_digit", TRUE);
}
else if (base != 16) {
RETURN_BOOL("is_base_digit", FALSE);
}
else if (ch >= 'a' && ch <= 'f') {
digit_val = ch - 'a' + 10;
RETURN_BOOL("is_base_digit", TRUE);
}
else {
digit_val = ch - 'A' + 10;
RETURN_BOOL("is_base_digit", ch >= 'A' && ch <= 'F');
}
}
/*
Copy string s2 to string s1 in reverse order.
*/
void
revcpy(char *s1, char *s2)
{
int length;
SL_DISABLE();
length = str_len(s2);
s2 = s2 + length - 1;
for (; length; length--) {
*s1++ = *s2--;
}
*s1 = '\0';
TRACEP("revcpy", printf("revcpy copy returns s1 = <%s>\n", s1));
}
/*
Get value of a string of digits into t_value.
Continue until a non base digit is found.
*/
void
scan_number(register int base)
{
SL_DISABLE();
t_value = 0;
while (is_base_digit(base)) {
t_value = ((long)base * t_value) + (long)digit_val;
sysnext();
}
TRACEP("scan_number",
printf("scan_number sets t_value: %ld\n", t_value));
}
/*
Skip blanks and tabs, but not newlines.
*/
void
skip_bl(void)
{
STAT("skip_bl");
while (ch == ' ' || ch == '\t') {
sysnext();
}
}
/*
Skip a newline, optionally preceeded or followed by '\r'.
Return TRUE if seen.
*/
bool
skip_crlf(void)
{
STAT("skip_crlf");
if (ch == '\r') {
sysnext();
if (ch == '\n') {
sysnext();
return TRUE;
}
else {
return FALSE;
}
}
else if (ch == '\n') {
sysnext();
if (ch == '\r') {
sysnext();
}
return TRUE;
}
else {
return FALSE;
}
}
/*
Skip characters up to but NOT including a newline.
*/
void
skip_1line(void)
{
STAT("skip_1line");
while (ch != END_FILE && ch != '\n') {
sysnext();
}
}
/*
Skip characters up to and including a newline.
*/
void
skip_past(void)
{
STAT("skip_past");
while (ch != END_FILE && ch != '\n') {
sysnext();
}
if (ch == '\n') {
sysnext();
do_nl();
}
}
/*
Skip to the end of the current preprocessor directive.
Do NOT skip past the final newline.
Note that directives may contain comments (!!) and may be continued
from line to line.
*/
void
skip_pp(void)
{
STAT("skip_pp");
for (;;) {
skip_ws();
if (ch == '\\') {
sysnext();
if (!skip_crlf()) {
/* Skip the escaped character. */
sysnext();
}
}
else if (ch == END_FILE || ch == '\n') {
return;
}
else {
sysnext();
}
}
}
/*
Skip blanks, tabs and comments.
*/
void
skip_ws(void)
{
STAT("skip_ws");
for(;;) {
switch(ch) {
case ' ':
case '\t':
sysnext();
continue;
case '/':
sysnext();
if (ch == '*') {
sysnext();
t_comment();
continue;
}
else {
syspush(ch);
ch = '/';
return;
}
default:
return;
}
}
}
/*
Process a non-fatal error messages.
*/
void
t_error(char * message)
{
SL_DISABLE();
(void) syscsts();
t_errcount++;
printf("line %3d, %s: %s\n", t_line, t_file, message);
}
void
t_2error(char * mess1, char *mess2)
{
SL_DISABLE();
(void) syscsts();
t_errcount++;
printf("line %3d, %s: %s%s\n", t_line, t_file, mess1, mess2);
}
void
t_3serr(struct node *p, char * mess1, char *mess2, char *mess3)
{
SL_DISABLE();
t_errcount++;
(void) syscsts();
printf("line %3d, %s: %s%s%s", t_line, t_file, mess1, mess2, mess3);
if (p) {
printf(" (see line %d)\n", p -> n_linno);
}
else {
printf("\n");
}
}
/*
Process a warning message.
*/
void
t_warning(char * message)
{
SL_DISABLE();
printf("line %3d, %s (warning): %s\n", t_line, t_file, message);
}
void
t_2warning(char * mess1, char *mess2)
{
SL_DISABLE();
printf("line %3d, %s (warning): %s%s\n", t_line, t_file, mess1, mess2);
}
/*
Process a less-important warning message.
*/
void
t_help(char * message)
{
SL_DISABLE();
printf("line %3d, %s (note): %s\n", t_line, t_file, message);
}
void
t_2help(char * mess1, char *mess2)
{
SL_DISABLE();
printf("line %3d, %s (note): %s%s\n", t_line, t_file, mess1, mess2);
}
/*
Code generation errors
*/
void
g_error(struct node * p, char * message)
{
SL_DISABLE();
if (p != NULL) {
printf("g_error/line %d file %s: %s\n",
p -> n_linno, "??", message);
}
else {
printf("g_error/line ?? file ??: %s\n", message);
}
}
/*
Process a less-important warning message.
*/
void
g_help(struct node *p, char * message)
{
SL_DISABLE();
if (p != NULL) {
printf("g_help/line %3d file %s (note): %s\n",
p -> n_linno, "??", message);
}
else {
printf("g_help/line ?? file ??: %s\n", message);
}
}
/*
Re-evaluate a string constant; this may shorten it
Return its length; it may contain imbedded zeroes once processed
CAUTION: if the string is transformed, it is always shortened. Callers
of this routine may count on that fact.
*/
unsigned int
str_val(register unsigned char *d)
{
register unsigned char val, *dd, *s;
TRACEPB("str_val", printf("(%s)\n", d));
/* outer loop to scan the string */
s = dd = d;
while (*s) {
if (*s != '\\') {
*d++ = *s++;
continue;
}
++s;
switch (*s) {
case 'b': *d++ = '\b'; ++s; break;
case 'f': *d++ = '\f'; ++s; break;
case 'n': *d++ = '\n'; ++s; break;
case 'r': *d++ = '\r'; ++s; break;
case 't': *d++ = '\t'; ++s; break;
case '\'': *d++ = '\''; ++s; break;
case '\\': *d++ = '\\'; ++s; break;
default:
if (*s < '0' || *s > '7') {
continue;
}
val = 0;
while (*s >= '0' && *s <= '7') {
val = val * 8 + *s - '0';
s++;
}
*d++ = val;
}
}
*d++ = '\0';
RETURN_UINT("str_val", (unsigned int)(d - dd));
}